

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="风间">
  <meta name="keywords" content="">
  
    <meta name="description" content="1. 重新认识 IoC   内容 说明    IoC 发展简介 包括 IoC 的定义以及它的一个简史   IoC 主要实现策略 其实 IoC 不只是我们所看到的包括 Martin Fowler 或者是像 Spring 官方的它的一个讨论   IoC 容器的职责 有多方解读来进行说明   IoC 容器的实现 包括了我们的开源实现和传统实现   传统 IoC 容器实现 着重介绍就是一种关于Java B">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring 核心编程思想（二）：重新认识 IoC">
<meta property="og:url" content="http://example.com/2023/05/08/%E5%90%8E%E7%AB%AF/java/spring%E6%A0%B8%E5%BF%83%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3%EF%BC%88%E4%BA%8C%EF%BC%89/index.html">
<meta property="og:site_name" content="风间小栈">
<meta property="og:description" content="1. 重新认识 IoC   内容 说明    IoC 发展简介 包括 IoC 的定义以及它的一个简史   IoC 主要实现策略 其实 IoC 不只是我们所看到的包括 Martin Fowler 或者是像 Spring 官方的它的一个讨论   IoC 容器的职责 有多方解读来进行说明   IoC 容器的实现 包括了我们的开源实现和传统实现   传统 IoC 容器实现 着重介绍就是一种关于Java B">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://s3.bmp.ovh/imgs/2023/05/06/43c27790d5a8ea71.jpg">
<meta property="article:published_time" content="2023-05-08T01:46:03.865Z">
<meta property="article:modified_time" content="2023-05-09T05:06:09.220Z">
<meta property="article:author" content="风间">
<meta property="article:tag" content="spring">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://s3.bmp.ovh/imgs/2023/05/06/43c27790d5a8ea71.jpg">
  
  
  <title>Spring 核心编程思想（二）：重新认识 IoC - 风间小栈</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hint.css@2/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.8.13","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":"§"},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>风间小栈</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/%E6%96%87%E6%9C%AC.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Spring 核心编程思想（二）：重新认识 IoC">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2023-05-08 09:46" pubdate>
        2023年5月8日 上午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      13k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      107 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Spring 核心编程思想（二）：重新认识 IoC</h1>
            
            <div class="markdown-body">
              <h2 id="1-重新认识-IoC"><a href="#1-重新认识-IoC" class="headerlink" title="1. 重新认识 IoC"></a>1. 重新认识 IoC</h2><table>
<thead>
<tr>
<th>内容</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>IoC 发展简介</td>
<td>包括 IoC 的定义以及它的一个简史</td>
</tr>
<tr>
<td>IoC 主要实现策略</td>
<td>其实 IoC 不只是我们所看到的包括 Martin Fowler 或者是像 Spring 官方的它的一个讨论</td>
</tr>
<tr>
<td>IoC 容器的职责</td>
<td>有多方解读来进行说明</td>
</tr>
<tr>
<td>IoC 容器的实现</td>
<td>包括了我们的开源实现和传统实现</td>
</tr>
<tr>
<td>传统 IoC 容器实现</td>
<td>着重介绍就是一种关于Java Beans 对 IoC 的容器的一个实现</td>
</tr>
<tr>
<td>轻量级 IoC 容器</td>
<td>如何定义以及它给我们带来的好处，有什么值得我们学习的地方</td>
</tr>
<tr>
<td>依赖查找 VS 依赖注入</td>
<td>为什么我们说Spring框架里面会偏好于依赖注入而非依赖查找</td>
</tr>
<tr>
<td>构造器注入 VS Setter注入</td>
<td>关于构造器注入和 Setter 方法注入的一个区别和优势</td>
</tr>
<tr>
<td>面试题精选</td>
<td>-</td>
</tr>
</tbody></table>
<h2 id="2-IoC-发展简介"><a href="#2-IoC-发展简介" class="headerlink" title="2. IoC 发展简介"></a>2. IoC 发展简介</h2><h3 id="2-1-什么是-IoC"><a href="#2-1-什么是-IoC" class="headerlink" title="2.1 什么是 IoC?"></a>2.1 什么是 IoC?</h3><p>In software engineering, inversion of control (IoC) is a programmiing principle. IoC inverts the flow of control as compared to traditional control flow. In IoC, custom-wvritten portions of a computer program receive the flow of control from a generic framework. Asoftware architecture with this design inverts</p>
<p>control as compared to traditional procedural programming: in traaditional programming, the custom code that expresses the purpose of the program calls into </p>
<p>reusable libraries to take care of generic tasks, but with inversion of control, it is the framework that calls into the custom,or task-specific,code.</p>
<p>在软件工程中，控制反转（IoC）是一种编程原则。与传统的控制流相比，IoC 反转了控制流。在 IoC 中，计算机程序的自定义部分从通用框架接收控制流。具有这种设计的软件架构与传统的过程式编程相比，控</p>
<p>制被反转了：在传统的编程中，表达程序目的的自定义代码调用可重用库来处理通用任务，但是在控制反转中，是框架调用自定义或特定任务的代码。</p>
<p>​                                                                                                       来源:<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Inversion_of_control">https://en.wikipedia.org/wiki/Inversion_of_control</a></p>
<h3 id="2-2-发展简介"><a href="#2-2-发展简介" class="headerlink" title="2.2 发展简介"></a>2.2 发展简介</h3><p>1983 年,Richard E. Sweet 在《The Mesa Programming Environment》中提出”Hollywood Principle”(好莱坞原则)</p>
<p>1988 年,Ralph E.Johnson&amp;Brian Foote在《Designing ReusableClasses》中提出”Inversion of control”(控制反转)</p>
<p>1996 年,Michael Mattson 在《Object-Oriented Frameworks, Asurvey of methodological issues》中将 “Inversion of control” 命名为 “Hollywood principle”</p>
<p><font color="red">2004 年,Martin Fowler 在《Inversion of Control Containers andthe Dependency Injectionpattern》中提出了自己对 IoC 以及 DI 的理解</font></p>
<p>2005 年,Martin Fowler 在《Inversion of Control》对 IoC 做出进一步的说明</p>
<h2 id="3-IoC-主要实现策略"><a href="#3-IoC-主要实现策略" class="headerlink" title="3. IoC 主要实现策略"></a>3. IoC 主要实现策略</h2><ul>
<li><p>维基百科(<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Inversion_of_control">https://en.wikipedia.org/wiki/Inversion_of_control</a>)</p>
<p>Implementation techniques小节的定义:</p>
<p>“In object-oriented programming, there are several basic techniquees to implement inversion of control. These are:</p>
<ul>
<li>Using a service IoCator pattern：服务定位模式，这种模式是 JavaEE 里面所定义的一种模式，通常通过 JNDI 这种技术获取 JavaEE 的组件，比如说获取 EJB 组件或者 DataSource 这样的东西</li>
<li>Using dependency injection, for example：依赖注入<ul>
<li>Constructor injection：构造器注入</li>
<li>Parameter injection：参数注入</li>
<li>Setter injection：set 方法注入</li>
<li>Interface injection：接口注入</li>
</ul>
</li>
<li>Using a contextualized lookup：上下文依赖查询，由另外一种技术来进行实现，比如说在 Java 里面有 Java Beans 这样的技术，Java Beans 里面有一个通用的上下文叫做 bean context，这种里面既可以传输我的 Bean 也可以来管理我的Bean的层次性</li>
<li>Using template method design pattern：关于模板方法的一个设计模式，这种设计模式在Spring里面大量地会用到，比如说是SpringJDBC里面会用到，JDBC Template这样的实现会给我们一种类似于比如说Statement这样的Callback这种Callback能够帮助我们实现地更为抽象，当我们去实现这样的接口的时候我们不需要关心Callback从哪来，那么也实现了一种反转控制的方式</li>
<li>Using strategy design pattern:策略模式”</li>
</ul>
</li>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>》提到的主要实现策略:</p>
<p>“IoC is a broad concept that can be implemented in different ways. There are two main types:</p>
<p><strong>Dependency Lookup（依赖查找）</strong>: The container provides callbacks to components, and a lookup context. This is</p>
<p>the EJB and Apache Avalon approach. It leaves the onus each component to use container APls</p>
<p>look up resources and collaborators. The Inversion of Control is limited to the container invoking</p>
<p>callback methods that application code can use to obtain resources.</p>
<p><strong>Dependency Injection（依赖注入）</strong>: Components do no look up; they provide plain Java methods enabling the</p>
<p>container to resolve dependencies. The container is wholly responsible for wiring up components,</p>
<p>passing resolved objects in to JavaBean properties or constructors. Use of JavaBean properties is</p>
<p>called Setter Injection; use of constructor arguments is called Constructor Injection.”</p>
</li>
</ul>
<h2 id="4-IoC-容器的职责"><a href="#4-IoC-容器的职责" class="headerlink" title="4. IoC 容器的职责"></a>4. IoC 容器的职责</h2><ol>
<li>维基百科(<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Inversion_of_control">https://en.wikipedia.org/wiki/Inversion_of_control</a>)</li>
</ol>
<p>在Overview小节中提到:</p>
<p>“Inversion of control serves the following design purposes:</p>
<ul>
<li>To decouple（解耦） the execution of a task from implementation.</li>
<li>To focus a module on the task it is designed for.</li>
<li>To free modules from assumptions about how other systems do what they do and instead rely on<br>contracts.</li>
<li>To prevent side effects when replacing a module.</li>
</ul>
<p>Inversion of control is sometimes facetiously referred to as the ‘Hollywood Principle: Don’t call us, we’ll<br>call you’.”</p>
<ul>
<li>通用职责</li>
<li>依赖处理<ul>
<li>依赖查找</li>
<li>依赖注入</li>
</ul>
</li>
<li>生命周期管理<ul>
<li>容器</li>
<li>托管的资源(JavaBeans 或其他资源)</li>
</ul>
</li>
<li>配置<ul>
<li>容器</li>
<li>外部化配置</li>
<li>托管的资源(JavaBeans 或其他资源)</li>
</ul>
</li>
</ul>
<h2 id="5-IoC-容器的实现"><a href="#5-IoC-容器的实现" class="headerlink" title="5. IoC 容器的实现"></a>5. IoC 容器的实现</h2><ul>
<li>主要实现<ul>
<li>Java SE<ul>
<li>Java Beans</li>
<li>Java ServiceLoader SPl</li>
<li>JNDI (Java Naming and Directory Interface)</li>
</ul>
</li>
<li>Java EE<ul>
<li>EJB (Enterprise Java Beans)</li>
<li>Servlet</li>
</ul>
</li>
<li>开源<ul>
<li>Apache Avalon (<a target="_blank" rel="noopener" href="http://avalon.apache.org/closed.html">http://avalon.apache.org/closed.html</a>)</li>
<li>PicoContainer (<a target="_blank" rel="noopener" href="http://picocontainer.com/">http://picocontainer.com/</a>)</li>
<li>Google Guice (<a target="_blank" rel="noopener" href="https://github.com/google/guice">https://github.com/google/guice</a>)</li>
<li>Spring Framework (<a target="_blank" rel="noopener" href="https://spring.io/projects/spring-framework">https://spring.io/projects/spring-framework</a>)</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="6-传统-IoC-容器实现：Java-Beans"><a href="#6-传统-IoC-容器实现：Java-Beans" class="headerlink" title="6. 传统 IoC 容器实现：Java Beans"></a>6. 传统 IoC 容器实现：Java Beans</h2><ul>
<li><p>特性</p>
<ul>
<li>依赖查找</li>
<li>生命周期管理</li>
<li>配置元信息</li>
<li>事件</li>
<li>自定义</li>
<li>资源管理</li>
<li>持久化</li>
</ul>
</li>
<li><p>规范</p>
<ul>
<li>JavaBeans: <a target="_blank" rel="noopener" href="https://www.oracle.com/technetwork/java/javase/tech/index-jsp-138795.html">https://www.oracle.com/technetwork/java/javase/tech/index-jsp-138795.html</a></li>
<li>BeanContext: <a target="_blank" rel="noopener" href="https://docs.oracle.com/javase/8/docs/technotes/guides/beans/spec/beancontext.htm">https://docs.oracle.com/javase/8/docs/technotes/guides/beans/spec/beancontext.htm</a></li>
</ul>
</li>
<li><p>Java Beans 实战</p>
<p>通常来说对于 Java Bean 的理解可以认为是一个简单的 POJO，但是对 Java Bean 的理解可以了解得更多</p>
<ul>
<li><p>新建 maven 项目 java-beans-demo</p>
</li>
<li><p>新建 Person 类 </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> tech.fengjian.ioc.java.beans;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 描述人的 POJO 类</span><br><span class="hljs-comment"> * &lt;p&gt;</span><br><span class="hljs-comment"> * POJO: Setter/Getter方法</span><br><span class="hljs-comment"> * Java Beans：可写方法(Writable)/可读方法(Readable)</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span> </span>&#123;<br><br>    <span class="hljs-keyword">private</span> String name;<span class="hljs-comment">// Property</span><br>    <span class="hljs-keyword">private</span> Integer age;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> name;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.name = name;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> Integer <span class="hljs-title">getAge</span><span class="hljs-params">()</span> </span>&#123;<br>        <span class="hljs-keyword">return</span> age;<br>    &#125;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setAge</span><span class="hljs-params">(Integer age)</span> </span>&#123;<br>        <span class="hljs-keyword">this</span>.age = age;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>新建 BeanInfoDemo 类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> tech.fengjian.ioc.java.beans;<br><br><span class="hljs-keyword">import</span> java.beans.BeanInfo;<br><span class="hljs-keyword">import</span> java.beans.IntrospectionException;<br><span class="hljs-keyword">import</span> java.beans.Introspector;<br><span class="hljs-keyword">import</span> java.util.Arrays;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * &#123;<span class="hljs-doctag">@link</span> java.beans.BeanInfo&#125; 示例</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BeanInfoDemo</span> </span>&#123;<br><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> IntrospectionException </span>&#123;<br><br>        <span class="hljs-comment">// 通过 Java Beans 自省操作定义 BeanInfo</span><br>        BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);<br><br>        Arrays.stream(beanInfo.getPropertyDescriptors()).forEach(propertyDescriptor -&gt; &#123;<br>            System.out.println(propertyDescriptor);<br>        &#125;);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>关于 BeanInfo 的解析</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> java.beans;<br><br><span class="hljs-keyword">import</span> java.awt.Image;<br><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">BeanInfo</span> </span>&#123;<br><br>    <span class="hljs-function">BeanDescriptor <span class="hljs-title">getBeanDescriptor</span><span class="hljs-params">()</span></span>;<br><br>    EventSetDescriptor[] getEventSetDescriptors();<br><br>    <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">getDefaultEventIndex</span><span class="hljs-params">()</span></span>;<br><br>    PropertyDescriptor[] getPropertyDescriptors();<br><br>    <span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">getDefaultPropertyIndex</span><span class="hljs-params">()</span></span>;<br><br>    MethodDescriptor[] getMethodDescriptors();<br><br>    BeanInfo[] getAdditionalBeanInfo();<br><br>    <span class="hljs-function">Image <span class="hljs-title">getIcon</span><span class="hljs-params">(<span class="hljs-keyword">int</span> iconKind)</span></span>;<br><br>&#125;<br><br></code></pre></td></tr></table></figure>

<p>这个类里会有一些描述：</p>
<ul>
<li><p>BeanDescriptor getBeanDescriptor();</p>
<p>Bean 的 Descriptor，那么 Bean 的 Descriptor 这里主要是指的一些Bean的基本的描述</p>
</li>
<li><p>EventSetDescriptor[] getEventSetDescriptors();</p>
<p>关于事件上的描述，那么这事件就包括我的事件的一个处理的方法</p>
</li>
<li><p>PropertyDescriptor[] getPropertyDescriptors();</p>
<p>还有就是关于我的 Property 描述器或者描述符，描述我们定义的写方法和读方法</p>
</li>
</ul>
</li>
<li><p>上面 BeanInfoDemo 输出结果：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java">java.beans.PropertyDescriptor[name=age; propertyType=<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">java</span>.<span class="hljs-title">lang</span>.<span class="hljs-title">Integer</span></span>; readMethod=<span class="hljs-keyword">public</span> java.lang.Integer tech.fengjian.ioc.java.beans.Person.getAge(); writeMethod=<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> tech.fengjian.ioc.java.beans.Person.setAge(java.lang.Integer)]<br>java.beans.PropertyDescriptor[name=<span class="hljs-class"><span class="hljs-keyword">class</span></span>; propertyType=<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">java</span>.<span class="hljs-title">lang</span>.<span class="hljs-title">Class</span></span>; readMethod=<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">native</span> java.lang.Class java.lang.Object.getClass()]<br>java.beans.PropertyDescriptor[name=name; propertyType=<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">java</span>.<span class="hljs-title">lang</span>.<span class="hljs-title">String</span></span>; readMethod=<span class="hljs-keyword">public</span> java.lang.String tech.fengjian.ioc.java.beans.Person.getName(); writeMethod=<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> tech.fengjian.ioc.java.beans.Person.setName(java.lang.String)]<br></code></pre></td></tr></table></figure>

<p>输出了 age、class、name 三个 Property 描述信息。这里多出了一个 class，这个是 Object 类中的 getClass 方法，跟定义 BeanInfo 的方法参数有关，若指定 stopClass 为 Object有，那么 class 就不会输出</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">BeanInfo beanInfo = Introspector.getBeanInfo(Person.class,Object.class);<br></code></pre></td></tr></table></figure></li>
</ul>
</li>
</ul>
<h2 id="7-轻量级-IoC-容器"><a href="#7-轻量级-IoC-容器" class="headerlink" title="7. 轻量级 IoC 容器"></a>7. 轻量级 IoC 容器</h2><ul>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>》认为轻量级容器的特征:</p>
<p>A container that can manage application code.能够管理到我的应用代码，并不是说我们是个代码的托管工具，它是说我们的容器可以管理代码运行，比如说可以控制代码的一个启停。</p>
<p>A container that is quick to start up.说它能够快速地启动。</p>
<p>A container that doesn’t require any special deployment steps to deploy objects within it.它不需要一些特殊的配置</p>
<p>A container that has such a light footprint and minimal API dependencies that it can be run in a variety of environments.容器它能够达到一些比较轻量级的内存占用,以及最小化的 API 的一个依赖</p>
<p>A container that sets the bar for adding a managed object so low in terms of deployment effort and performance. overhead that it’s possible to deploy and</p>
<p>manage fine-grained objects, as well as coarse-grained components.</p>
<p>容器就需要一些可以管控的这么一个渠道去部署和管理一些细粒度的对象甚至是一些粗粒度的组件，主要它是要达到一些部署上的一个效率以及相关的性能上面的一个开销，那么是它对相当于容器的一个补充说明。</p>
</li>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>》认为轻量级容器的好处：</p>
<p>Escaping the monolithic container 释放掉一些容器，就所谓的聚式或者是单体这样的容器，monolithic 这种单词就是聚式或者说我们的单体应用</p>
<p>Maximizing codereusability 要实现最大化的一个代码的复用</p>
<p>Greater object orientation 更大程度上面的面向对象</p>
<p>Greater productivity 更大化的一个产品化</p>
<p>Better testability 更好的可测试性</p>
</li>
</ul>
<h2 id="8-依赖查找-VS-依赖注入"><a href="#8-依赖查找-VS-依赖注入" class="headerlink" title="8. 依赖查找 VS 依赖注入"></a>8. 依赖查找 VS 依赖注入</h2><p>从 5 个纬度来进行对比：没有绝对的好与坏，只有相对的合理</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>依赖处理</th>
<th>实现便利性</th>
<th>代码侵入性</th>
<th>API 依赖性</th>
<th>可读性</th>
</tr>
</thead>
<tbody><tr>
<td>依赖查找</td>
<td>主动获取</td>
<td>相对繁琐</td>
<td>侵入业务逻辑</td>
<td>依赖容器 API</td>
<td>良好</td>
</tr>
<tr>
<td>依赖注入</td>
<td>被动提供</td>
<td>相对便利</td>
<td>低侵入性</td>
<td>不依赖容器 API</td>
<td>一般</td>
</tr>
</tbody></table>
<h2 id="9-构造器注入-VS-Setter注入"><a href="#9-构造器注入-VS-Setter注入" class="headerlink" title="9. 构造器注入 VS Setter注入"></a>9. 构造器注入 VS Setter注入</h2><ul>
<li><p>Spring Framework 对构造器注入与 Setter 的论点:</p>
<p>“The Spring team generally <font color="red">advocates constructor injection</font>, as it lets you implement application components as immutable objects and ensures that required </p>
<p>dependencies are not null. Furthermore, constructor-injected components are always returned to the client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments a bad code smell, implying that the class likely has too many responsibilities and should be refactored</p>
<p>to better address proper separation of concerns.</p>
<p>Spring 团队通常倡导使用构造函数注入（constructor injection），因为它可以让你把应用组件实现为不可变对象，并确保必需的依赖项不为空。此外，构造函数注入的组件总是以完全初始化的状态返回给客户端代码（调用方）。一个额外的说明是，大量的构造函数参数是一种不好的代码气味，意味着这个类可能有太多的职责，应该进行重构，以更好地实现关注点分离。</p>
<p><font color="red"> Setter injection should primarily only be used for optional dependencies</font> that can be assigned reasonable default values within </p>
<p>the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods</p>
<p>make objects of that class amenable to reconfiguration or re-injection later Management through JMX MBeans is therefore a compelling use case for setter</p>
<p>injection.”</p>
<p>Setter 注入应主要仅用于可以在类内分配合理默认值的可选依赖项。否则，在代码使用该依赖项的所有地方都必须执行非空检查。 Setter 注入的一个好处是，setter 方法使得那个类的对象容易在以后进行重新配置或重新注入。因此，通过JMX MBeans进行管理是 Setter 注入的一个很好的用例。</p>
</li>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>)认为 Setter 注入的优点:</p>
<p>“<font color="red">Advantages of Setter Injection</font> include:</p>
<ul>
<li><p>JavaBean properties are <font color="red">well supported</font> in IDES.</p>
</li>
<li><p>JavaBean properties are <font color="red">self-documenting</font>.</p>
</li>
<li><p>JavaBean properties are inherited by subclasses without the need for any code</p>
</li>
<li><p>It’s possible to use <font color="red">the standard JavaBeans property-editor machinery for type conversions</font> if necessary</p>
</li>
<li><p>Many existing JavaBeans can be used within a JavaBean-oriented IoC container without modification</p>
</li>
<li><p>If there is a corresponding getter for each setter (making the property readable, as well as writable), it is possible to ask</p>
</li>
</ul>
<p>the component for its current configuration state. This is particularly useful if we want to persist that state: for example,</p>
<p>in an XML form or in a database. With Constructor Injection, there’s no way to find the current state.</p>
<ul>
<li>Setter Injection works well for objects that have default values, meaning that not all properties need to be supplied at</li>
</ul>
<p>runtime.”</p>
<p>Setter 注入的优点包括：</p>
<ul>
<li><p>JavaBean 属性在 IDE 中获得很好的支持。</p>
</li>
<li><p>JavaBean 属性是自我记录的。</p>
</li>
<li><p>JavaBean 属性被子类继承，无需任何代码。</p>
</li>
<li><p>如有必要，可以使用标准的 JavaBeans 属性编辑器机制进行类型转换。</p>
</li>
<li><p>许多现有的 JavaBeans 可以在 JavaBean 导向的 IoC 容器中使用而无需修改。</p>
</li>
<li><p>如果每个 setter 都有相应的 getter（使属性可读和可写），则可以询问组件其当前配置状态。如果想要保存该状态，这非常有用，例如在XML表单或数据库中。使用构造函数注入，没有办法找到当前状态。</p>
</li>
<li><p>Setter 注入适用于具有默认值的对象，这意味着不需要在运行时提供所有属性。</p>
</li>
</ul>
</li>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>》认为 Setter 注入的缺点:</p>
<p>“<font color="red">Disadvantages</font> include:</p>
<p>The order in which setters are called is not expressed in any contract. Thus, we sometimes need to invoke a method after the last setter has been called to initialize the component. Spring provides the <code>org.springframework.beans.factory.InitializingBean</code> interface for this; it also provides the ability to invoke an arbitrary init method. However, this contract must be documented to ensure correct use outside a container. Not all the necessary setters may have been called before use. The object can thus be left partially configured.”</p>
<p>缺点包括：</p>
<p>在任何契约中都没有表达调用 setter 的顺序。因此，我们有时需要在最后一个 setter 被调用之后调用方法来初始化组件。Spring 提供了<code>org.springframework.beans.factory.InitializingBean</code> 接口和调用任意初始化方法的能力。然而，这个契约必须被记录以确保在容器之外正确使用。在使用之前可能没有调用所有必要的setter，因此对象可能会部分配置不完整。</p>
</li>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>》认为构造器注入的优点:<br>“<font color="red">Advantages of Constructor Injection</font> include:</p>
<ul>
<li>Each managed object is guaranteed to be in a consistent state-fully configured-before it can be invoked in any<br>business methods. This is the primary motivation of Constructtor Injection. (However, it is possible to achieve the<br>same result with JavaBeans via dependency checking, as Spring can optionally perform.) There’s no need for<br>initialization methods.</li>
<li>There may be slightly less code than results from the useof multiple JavaBean methods, although will be no<br>difference in complexity.”</li>
</ul>
</li>
<li><p>《Expert One-on-One<sup>TM</sup> J2EE<sup>TM</sup> Development without EJB<sup>TM</sup>)认为构造器注入的缺点:<br>“<font color="red">Disadvantages</font> include:</p>
<ul>
<li>Although also a Java-language feature, multi-argument coonstructors are probably less common in existing code thause<br>of JavaBean properties.</li>
<li>Java constructor arguments don’t have names visible by introspection</li>
<li>Constructor argument lists are less well supported by IDEs tharJavaBean setter methods.</li>
<li>Long constructor argument lists and large constructor bodies can become unwieldy</li>
<li>Concrete inheritance can become problematic.</li>
<li>Poor support for optional properties, compared to JavaBeaans</li>
<li>Unittesting can be slightly more difficult</li>
<li>When collaborators are passed in on object construction, it becomes impossible to change the reference held in the<br>object.”</li>
</ul>
</li>
</ul>
<h2 id="10-面试题"><a href="#10-面试题" class="headerlink" title="10. 面试题"></a>10. 面试题</h2><p><strong><font color="green" size="2">沙雕面试题</font></strong>-什么是 IoC？</p>
<p>答:</p>
<p>简单地说,IoC 是反转控制,类似于好莱坞原则,主要有依赖查找和依赖注入实现，</p>
<p>进一步说的话：按照IoC的定义很多方面都是IoC,我们常说的比如说 JavaBeans 是 IoC 的一个容器实现、Servlet 的容器也是 IoC 的实现，因为 Servlet 可以去依赖或者反向地通过 JNDI 的方式进行得到一些外部的一些资源包括 DataSource 或者相关的 EJB 的组件，与此同时像是 Spring Framework 或者 PicoContainer 的依赖注入的框架也能够帮助我们去实现我们的IoC。同时除此之外这些东西是我们比较常见的一个 IoC 的实现策略。按照它这个定义如果是反转控制那东西就多了去了，包括我们说消息其实也算，因为消息其实是被动的我们如果说我们传统的调用链路是一个主动拉的模式那么 IoC 其实是一种推的模式，那么推的模式在消息事件以及各种这样类似于这种反向的观察者模式的扩展都属于 IoC 那么这东西就无穷无尽了，那么它如果仅仅关注于依赖注入比如说通过构造器注入或 Setter 注入，那么它其中有什么好处。</p>
<p><strong><font color="orange" size="2">996面试题</font></strong>-依赖查找和依赖注入的区别？</p>
<p>答:依赖查找是主动或手动的依赖查找方式,通常需要依赖容器或标准 API 实现。而依赖注入则是手动或自动依赖绑定的方式,无需依赖特定的容器和 API。</p>
<p><strong><font color="red" size="2">劝退面试题</font></strong>-Spring 作为 IoC 容器有什么优势？</p>
<p>答:<br>典型的 IoC 管理,依赖查找和依赖注入</p>
<p>AOP 抽象</p>
<p>事务抽象</p>
<p>事件机制</p>
<p>SPI 扩展</p>
<p>强大的第三方整合</p>
<p>易测试性</p>
<p>更好的面向对象</p>
<p><strong>本节完</strong></p>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/%E5%90%8E%E7%AB%AF/">后端</a>
                    
                      <a class="hover-with-bg" href="/categories/%E5%90%8E%E7%AB%AF/spring-%E6%A0%B8%E5%BF%83%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3/">spring 核心编程思想</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/spring/">spring</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2023/05/08/%E5%90%8E%E7%AB%AF/java/spring%E6%A0%B8%E5%BF%83%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3%EF%BC%88%E4%B8%89%EF%BC%89/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">Spring 核心编程思想（三）：Spring IoC 容器概述</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2023/05/08/%E5%90%8E%E7%AB%AF/java/vue3/">
                        <span class="hidden-mobile">玩转 vue3</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments" lazyload>
                
                  
                
                
  <div id="SOHUCS" sid='http://example.com/2023/05/08/%E5%90%8E%E7%AB%AF/java/spring%E6%A0%B8%E5%BF%83%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3%EF%BC%88%E4%BA%8C%EF%BC%89/'></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#SOHUCS', function() {
      Fluid.utils.createScript("https://changyan.sohu.com/upload/changyan.js", function() {
        window.changyan.api.config({"appid":"cywjv2D9l","appkey":"2bf2f1231299e92b26393ba6fb2ad9d8"})
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
    风间小栈出品
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
        typing(title);
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
